package com.xusheng.cli.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.xusheng.cli.common.base.MyServiceImpl;
import com.xusheng.cli.common.constant.Constant;
import com.xusheng.cli.common.constant.Regular;
import com.xusheng.cli.common.enums.ResultEnum;
import com.xusheng.cli.common.exception.ServiceException;
import com.xusheng.cli.entity.userModule.AdminMenuVO;
import com.xusheng.cli.entity.userModule.AssociatedRoleDTO;
import com.xusheng.cli.entity.userModule.PasswordDTO;
import com.xusheng.cli.entity.userModule.User;
import com.xusheng.cli.mapper.UserMapper;
import com.xusheng.cli.service.RoleService;
import com.xusheng.cli.service.UserService;
import com.xusheng.cli.tools.CurrentUserUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 总后台用户表(User)表服务实现类
 *
 * @author jy
 * @since 2022-01-17 12:08:46
 */
@Service("userService")
public class UserServiceImpl extends MyServiceImpl<UserMapper, User> implements UserService {

	@Resource
	private RoleService roleService;

	@Override
	public String getIpWhitelist(Long id) {
		return baseMapper.getIpWhitelist(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean setIpWhitelist(String ipWhitelist) {
		return baseMapper.setIpWhitelist(ipWhitelist, CurrentUserUtil.getUserId());
	}

	/**
	 * 修改当前登录人密码
	 *
	 * @param passwordDTO
	 * @author jy
	 * @since 2022/1/17 13:17
	 */
	@Override
	public boolean setPassword(PasswordDTO passwordDTO) {
		Long userId = CurrentUserUtil.getUserId();
		User user = baseMapper.selectById(userId);
		if (!DigestUtil.bcryptCheck(passwordDTO.getOldPassword(), user.getPassword())) {
			throw new ServiceException("旧密码不正确");
		}
		else {
			user.setPassword((DigestUtil.bcrypt(passwordDTO.getNewPassword())));
			return SqlHelper.retBool(baseMapper.updateById(user));
		}
	}

	/**
	 * 用户指定角色
	 *
	 * @param associatedRoleDTO
	 * @return
	 */
	@Override
	public boolean associatedRole(AssociatedRoleDTO associatedRoleDTO) {
		baseMapper.removeAssociatedRole(associatedRoleDTO);
		boolean res = SqlHelper.retBool(baseMapper.associatedRole(associatedRoleDTO));
		if (res) {
			//删除该用户登录的角色权限
			SaSession session = StpUtil.getSessionByLoginId(associatedRoleDTO.getAccId(), false);
			if (null != session) {
				session.delete("Role_List");
			}
		}
		return res;
	}

	/**
	 * 启禁用账户
	 *
	 * @param accountId 账户id
	 * @author jy
	 * @since 2022/1/17 13:45
	 */
	@Override
	public boolean disOrEnaAccount(Long accountId) {
		User user = new User();
		LambdaUpdateWrapper<User> updateWrapper = Wrappers.lambdaUpdate();
		updateWrapper.eq(User::getInitial, false).setSql("enable = not enable").eq(User::getId, accountId);
		return SqlHelper.retBool(baseMapper.update(user, updateWrapper));
	}

	/**
	 * 获取当前登录人菜单
	 *
	 * @author jy
	 * @since 2022/1/17 13:49
	 */
	@Override
	public List<AdminMenuVO> getMenuList() {
		List<AdminMenuVO> menuList = baseMapper.getMenuListByUserId(CurrentUserUtil.getUserId());
		if (menuList.size() == 0) {
			return Collections.emptyList();
		}
		Map<Long, List<AdminMenuVO>> collect = menuList.stream().collect(Collectors.groupingBy(AdminMenuVO::getParentId));
		List<AdminMenuVO> parent = collect.get(0L);
		parseList(parent, collect);
		return parent;
	}

	/**
	 * 递归拼接菜单
	 */
	private void parseList(List<AdminMenuVO> parent, Map<Long, List<AdminMenuVO>> permissions) {
		for (AdminMenuVO adminMenuVO : parent) {
			Long id = adminMenuVO.getPermissionId();
			List<AdminMenuVO> children = permissions.get(id);
			if (CollectionUtil.isNotEmpty(children)) {
				adminMenuVO.setSubMenu(children);
				parseList(children, permissions);
			}
		}
	}

	/**
	 * 新增数据
	 *
	 * @param user
	 * @return
	 * @author jy
	 * @since 2022/1/17 14:17
	 */
	@Override
	public boolean insert(User user) {
		LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery();
		queryWrapper.eq(User::getAccount, user.getAccount());
		User exist = baseMapper.selectOne(queryWrapper);
		if (exist != null) {
			throw new ServiceException("当前账户已存在!");
		}
		user.setPassword(DigestUtil.bcrypt(user.getPassword()));
		user.setEnable(true);
		user.setInitial(false);
		int insert = baseMapper.insert(user);
		// 添加默认角色
		List<Object> roleIds = roleService.listDefaultRole();
		if (roleIds != null && roleIds.size() > 0) {
			baseMapper.associatedRole(new AssociatedRoleDTO(user.getId(), roleIds));
		}
		return SqlHelper.retBool(insert);
	}

	/**
	 * 修改数据
	 *
	 * @param user
	 * @return
	 * @author jy
	 * @since 2022/1/17 14:27
	 */
	@Override
	public boolean update(User user) {
		// 禁止修改账户名
		user.setAccount(null);
		String password = user.getPassword();
		if (StrUtil.isNotBlank(password)) {
			boolean match = ReUtil.isMatch(Regular.PASSWORD, password);
			if (!match) {
				throw new ServiceException(Regular.PASSWORD_MASSAGE, ResultEnum.PARAMETER_ERROR);
			}
			user.setPassword(DigestUtil.bcrypt(password));
		}
		return SqlHelper.retBool(baseMapper.updateById(user));
	}

	/**
	 * 批量设置内置账户
	 *
	 * @param idList 账户id
	 * @author jy
	 * @since 2022/1/17 14:50
	 */
	@Override
	public boolean setInitAccount(List<Long> idList) {
		if (idList.size() > 0) {
			//去除所有内置账户
			LambdaUpdateWrapper<User> updateWrapper = Wrappers.lambdaUpdate();
			updateWrapper.eq(User::getInitial, true).set(User::getInitial, false);
			User entity = new User();
			baseMapper.update(entity, updateWrapper);
			//重新分配内置账户
			LambdaUpdateWrapper<User> updateInitWrapper = Wrappers.lambdaUpdate();
			updateInitWrapper.in(User::getId, idList).set(User::getInitial, true);
			return SqlHelper.retBool(baseMapper.update(entity, updateInitWrapper));
		}
		return false;
	}

	/**
	 * 获取验证码
	 *
	 * @param response@return void
	 * @author jy
	 * @date 2019/12/12 10:27
	 */
	@Override
	public void getVerification(HttpServletResponse response) {
		//定义图形验证码的长、宽、验证码字符数、干扰元素个数
		LineCaptcha captcha = CaptchaUtil.createLineCaptcha(100, 32, 4, 4);
		try (ServletOutputStream outputStream = response.getOutputStream()) {
			Cookie cookie = new Cookie("verificationCode", captcha.getCode());
			cookie.setPath("/");
			cookie.setMaxAge(1800);
			response.addCookie(cookie);
			SaSession tokenSession = StpUtil.getTokenSession();
			tokenSession.delete(Constant.CAPTCHA_SESSION_KEY);
			tokenSession.set(Constant.CAPTCHA_SESSION_KEY, captcha.getCode());
			//图形验证码写出，可以写出到文件，也可以写出到流
			captcha.write(outputStream);
			outputStream.flush();
		} catch (IOException e) {
			log.error(e.getMessage());
		}

	}

	/**
	 * 通过userId 获取权限code
	 *
	 * @param id 用户id
	 * @return 权限code
	 * @author jy
	 * @since 2021/11/11 14:10
	 */
	@Override
	public List<String> roleCodeByUserId(Long id) {
		return baseMapper.selectRoleCodeByUserId(id);
	}

}

